#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>

#define DEBUG(fmt, ...)         \
    do{                         \
        if(if_debug)            \
            printk(KERN_INFO "DEBUG > " fmt, ##__VA_ARGS__);   \
    }while(0)

bool if_debug = false;
/*定义一个bool类型的变量，作为一个模块入参，在装载模块时可赋值*/
module_param(if_debug, bool, S_IRUSR);

/*方式1*/
#define USE_OLD_INTERFACE 0

#define CHRDEV_NAME "test_char_dev"
#if USE_OLD_INTERFACE
#define DEV_COUNT 1

/*定义一个字符设备*/
static struct cdev *char_dev;
#else
/*主设备号*/
static dev_t major;
#endif

/*设备号*/
static dev_t devno;
static struct class *test_char_dev_class;

static int test_open (struct inode *inode, struct file *file)
{
    DEBUG("open test..\r\n");

    return 0;
}

static int test_close (struct inode *inode, struct file *file)
{
    DEBUG("close test..\r\n");
    
    return 0;
}

static const struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = test_open,
    .release = test_close,
};

static int __init test_init(void)
{
#if USE_OLD_INTERFACE
    /*申请设备号*/
    alloc_chrdev_region(&devno,0,DEV_COUNT,CHRDEV_NAME);
    /*定义一个字符设备*/
    char_dev = cdev_alloc();
    /*绑定字符设备*/
    cdev_init(char_dev,&fops);
    /*注册字符设备*/
    cdev_add(char_dev,devno,DEV_COUNT);
#else
    major = register_chrdev(0,CHRDEV_NAME,&fops);
    devno = MKDEV(major,0);
#endif

    /*创建设备类*/
    test_char_dev_class = class_create(THIS_MODULE,"test_char_dev_class");
    /*创建设备*/
    device_create(test_char_dev_class,NULL,devno,NULL,CHRDEV_NAME);

    return 0;
}

static void __exit test_exit(void)
{
    /*销毁设备*/
    device_destroy(test_char_dev_class,devno);
    /*销毁设备类*/
    class_destroy(test_char_dev_class);

#if USE_OLD_INTERFACE
    /*注销一个字符设备*/
    cdev_del(char_dev);
    /*注销申请的设备号*/
    unregister_chrdev_region(devno,DEV_COUNT);
#else
    unregister_chrdev(major,CHRDEV_NAME);
#endif
}

/*此宏声明内核模块的初始化入口点*/
module_init(test_init);
/*此宏声明内核模块的退出入口点*/
module_exit(test_exit);

/*声明开源协议*/
MODULE_LICENSE("GPL");
/*声明作者*/
MODULE_AUTHOR("wei");
/*声明模块的描述*/
MODULE_DESCRIPTION("this is a test driver");
